package com.zbkj.service.service.monitor.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.zbkj.common.config.AliMqttConfig;
import com.zbkj.common.exception.AppException;
import com.zbkj.common.model.admin.SystemAdmin;
import com.zbkj.common.model.brand.Brand;
import com.zbkj.common.model.device.Device;
import com.zbkj.common.model.merchant.Merchant;
import com.zbkj.common.model.monitor.ZfbMonitorDeviceBind;
import com.zbkj.common.model.monitor.ZfbMonitorEquipment;
import com.zbkj.common.model.order.MerchantOrder;
import com.zbkj.common.model.order.Order;
import com.zbkj.common.model.order.OrderDetail;
import com.zbkj.common.model.product.Product;
import com.zbkj.common.monitorchannel.*;
import com.zbkj.common.monitorchannel.vo.*;
import com.zbkj.common.page.CommonPage;
import com.zbkj.common.page.PaginationUtil;
import com.zbkj.common.request.MonitorControlLightRequest;
import com.zbkj.common.request.MonitorControlLightUserinfoRequest;
import com.zbkj.common.request.monitor.*;
import com.zbkj.common.response.*;
import com.zbkj.common.response.monitor.ZfbMonitorEquipmentResponse;
import com.zbkj.common.result.CommonResultCode;
import com.zbkj.common.utils.RedisUtil;
import com.zbkj.common.utils.SecurityUtil;
import com.zbkj.common.vo.LoginUserVo;
import com.zbkj.common.vo.QrCodeVo;
import com.zbkj.service.dao.ProductDao;
import com.zbkj.service.dao.monitor.ZfbMonitorEquipmentMapper;
import com.zbkj.service.dao.monitor.ZfbMonitorOrderMapper;
import com.zbkj.service.dao.monitor.ZfbMonitorTrafficSetMealMapper;
import com.zbkj.service.monitor.MonitorChannelHandle;
import com.zbkj.service.service.*;
import com.zbkj.service.service.device.DeviceService;
import com.zbkj.service.service.device.MqttConfigService;
import com.zbkj.service.service.monitor.IZfbMonitorEquipmentService;
import com.zbkj.service.service.monitor.IZfbMonitorOpenCloseService;
import com.zbkj.service.service.monitor.ZfbMonitorDeviceStatusService;
import com.zbkj.service.util.BrandUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @ClassName: ZfbMonitorEquipmentServiceImpl
 * @Description: TODO
 * @Author: fanbing
 * @Date: 2024/6/29 13:06
 * @Version: V1.0
 **/
@Service
@Slf4j
public class ZfbMonitorEquipmentServiceImpl extends ServiceImpl<ZfbMonitorEquipmentMapper, ZfbMonitorEquipment> implements IZfbMonitorEquipmentService {

    @Autowired
    private ZfbMonitorEquipmentMapper zfbMonitorEquipmentMapper;

    @Autowired
    private MerchantService merchantService;

    @Autowired
    private ProductDao productDao;

    @Autowired
    private MonitorChannelHandle monitorChannelHandle;

    @Autowired
    private ProductService productService;

    @Autowired
    private IZfbMonitorEquipmentService zfbMonitorEquipmentService;


    @Autowired
    private ZfbMonitorOrderMapper zfbMonitorOrderMapper;
    @Autowired
    private ZfbMonitorTrafficSetMealMapper zfbMonitorTrafficSetMealMapper;

    @Autowired
    private IZfbMonitorOpenCloseService zfbMonitorOpenCloseService;

    @Autowired
    private BrandService brandService;

    @Autowired
    private QrCodeService qrCodeService;

    @Autowired
    private SystemAdminService systemAdminService;

    @Autowired
    private ZfbMonitorDeviceStatusService zfbMonitorDeviceStatusService;

    @Autowired
    private OrderDetailService orderDetailService;


    @Autowired
    private ZfbMonitorDeviceBindService zfbMonitorDeviceBindService;

    @Autowired
    private MerchantOrderService merchantOrderService;

    @Autowired
    private MqttConfigService mqttConfigService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private UserService userService;
    @Autowired
    private OrderTraceableRecordService orderTraceableRecordService;
    @Autowired
    private ZfbDeviceMatchLogService zfbDeviceMatchLogService;
    @Autowired
    private DeviceService deviceService;

    @Resource
    private RedisUtil redisUtil;
    @Autowired
    private AliMqttConfig aliMqttConfig;
    @Autowired
    private RedissonClient redissonClient;

    int minute = 1000;



    /**
     * 新增
     *
     * @param addRequest
     * @return
     */
    @Override
    public boolean addMonitorEquipment(ZfbMonitorEquipmentAddReq addRequest, SystemAdmin systemAdmin) {
        ZfbMonitorEquipment monitorEquipment = zfbMonitorEquipmentMapper.selectOne(new LambdaQueryWrapper<ZfbMonitorEquipment>()
                .eq(ZfbMonitorEquipment::getLicense, addRequest.getLicense()).last("limit 1"));
        if (ObjectUtil.isNotNull(monitorEquipment)) {
            Merchant merchant = merchantService.getById(monitorEquipment.getMerchantId());
            throw new AppException("[" + merchant.getName() + "]商户已存在该license");
        }
        log.info("#addMonitorEquipment#入参数:{}", JSON.toJSONString(addRequest));
        ZfbMonitorEquipment addEquipment = new ZfbMonitorEquipment();
        addEquipment.setEquipmentType(addRequest.getEquipmentType());
        addEquipment.setEquipmentName(addRequest.getEquipmentName());
        addEquipment.setLicense(addRequest.getLicense());
        addEquipment.setMerchantId(systemAdmin.getMerId());
        addEquipment.setCreateTime(LocalDateTime.now());
        addEquipment.setUpdateTime(LocalDateTime.now());

        boolean flag = zfbMonitorEquipmentMapper.insert(addEquipment) > 0;

        new Thread(()->{
            // zfbMonitorOpenCloseService.checkOpenOrClose(addRequest.getLicense(), systemAdmin.getMerId());
            // 获取设备过期信息
            Map<String, Object> expireInfo = zfbMonitorDeviceStatusService.getExpireTimeByLicense(addEquipment.getLicense());

            // 处理设备状态
            zfbMonitorDeviceStatusService.processDeviceStatus(addEquipment.getLicense(), expireInfo, null);
        }).start();

        return flag;
    }

    /**
     * 修改
     *
     * @param monitorEquipmentAddReq
     * @return
     */
    @Override
    public boolean editMonitorEquipment(ZfbMonitorEquipmentAddReq monitorEquipmentAddReq, SystemAdmin systemAdmin) {
        ZfbMonitorEquipment monitorEquipment = zfbMonitorEquipmentMapper.selectById(monitorEquipmentAddReq.getId());
        if (ObjectUtil.isNull(monitorEquipment)) {
            throw new AppException("id参数有误");
        }
        log.info("#editMonitorEquipment#入参数:{}", JSON.toJSONString(monitorEquipmentAddReq));
        monitorEquipment.setEquipmentName(monitorEquipmentAddReq.getEquipmentName());
        monitorEquipment.setUpdateTime(LocalDateTime.now());
        return zfbMonitorEquipmentMapper.updateById(monitorEquipment) > 0;

    }


    @Override
    public boolean deleteMonitorEquipment(ZfbMonitorEquipmentDeleteReq deleteRequest, SystemAdmin systemAdmin) {
        log.info("#deleteMonitorEquipment#删除设备 deleteRequest={};systemAdmin={}", JSON.toJSONString(deleteRequest), JSON.toJSONString(systemAdmin));
        ZfbMonitorEquipment monitorEquipment = zfbMonitorEquipmentMapper.selectOne(new LambdaQueryWrapper<ZfbMonitorEquipment>()
                .eq(ZfbMonitorEquipment::getLicense, deleteRequest.getLicense()).last("limit 1"));
        if (ObjectUtil.isNull(monitorEquipment)) {
            throw new AppException("该设备不存在无法删除");
        }
        if (!Objects.equals(systemAdmin.getMerId(), monitorEquipment.getMerchantId())) {
            throw new AppException("非当前用户设备，无法删除");
        }

        LambdaQueryWrapper<Product> lw = new LambdaQueryWrapper<>();
        lw.like(Product::getLicense, monitorEquipment.getLicense());
        List<Product> products = productDao.selectList(lw);
        if (!CollectionUtils.isEmpty(products)) {
            products.forEach(product -> {
                String licenseStr = product.getLicense();
                List<String> split = StrUtil.split(licenseStr, ',');
                List<String> newList = Lists.newArrayList();
                for (String license : split) {
                    if (!Objects.equals(license, monitorEquipment.getLicense())
                            && StrUtil.isNotBlank(license)) {
                        newList.add(license);
                    }
                }

                if (!CollectionUtils.isEmpty(newList)) {
                    product.setLicense(Joiner.on(",").join(newList));
                } else {
                    product.setLicense("");
                }


            });
            productService.updateBatchById(products);
        }

        productDao.cleanByLicense(monitorEquipment.getLicense());
        return zfbMonitorEquipmentMapper.deleteById(monitorEquipment.getId()) > 0;
    }

    /**
     * 商户监控列表
     *
     * @param searchRequest
     * @return
     */
    @Override
    public CommonPage<ZfbMonitorEquipmentResponse> getMerchantPageList(ZfbMonitorEquipmentSearchReq searchRequest, SystemAdmin systemAdmin) {
        Merchant merchant = merchantService.getById(systemAdmin.getMerId());

        LambdaQueryWrapper<ZfbMonitorEquipment> qw = new LambdaQueryWrapper<>();
        qw.eq(ZfbMonitorEquipment::getMerchantId, systemAdmin.getMerId());
        qw.like(StrUtil.isNotBlank(searchRequest.getEquipmentName()), ZfbMonitorEquipment::getEquipmentName, searchRequest.getEquipmentName());
        qw.eq(StrUtil.isNotBlank(searchRequest.getLicense()), ZfbMonitorEquipment::getLicense, searchRequest.getLicense());
        qw.eq(ObjectUtil.isNotNull(searchRequest.getEquipmentType()), ZfbMonitorEquipment::getEquipmentType, searchRequest.getEquipmentType());
        Page<ZfbMonitorEquipment> page = zfbMonitorEquipmentMapper.selectPage(new Page<>(searchRequest.getPage(), searchRequest.getLimit()), qw);
        List<ZfbMonitorEquipment> records = page.getRecords();

        CommonPage<ZfbMonitorEquipmentResponse> commonPage = PaginationUtil.convertAndFillPage(records, page, ZfbMonitorEquipmentResponse.class);
        commonPage.getList().forEach(response -> {
            response.setMerchant(merchant);
            try {
                MonitorChannelEquipmentStatusVo equipmentStatus = zfbMonitorEquipmentService.getEquipmentStatus(response.getLicense());
                if (ObjectUtil.isNotNull(equipmentStatus)) {
                    response.setEquipmentStatusVo(equipmentStatus);

                    GetDeviceModelV3Request request = new GetDeviceModelV3Request();
                    request.setDid(equipmentStatus.getDid());
                    GetDeviceModelModulesV3Request modelModulesV3Request = new GetDeviceModelModulesV3Request();
                    modelModulesV3Request.setAIIoTID("0");
                    modelModulesV3Request.setAIIoTType("1040");
                    GetDeviceModelModulesV3Request cameraParams = new GetDeviceModelModulesV3Request();
                    cameraParams.setAIIoTID("0");
                    cameraParams.setAIIoTType("1012");
                    request.setModules(Lists.newArrayList(modelModulesV3Request, cameraParams));
                    JSONObject jsonObject = zfbMonitorEquipmentService.GetDeviceModel(request, 0);
                    response.setDeviceModel(jsonObject);
                }
            } catch (Exception e) {
                log.error("查询设备数据异常", e);
            }

            Map<String, Object> map = zfbMonitorDeviceStatusService.getExpireTimeByLicense(response.getLicense());
            if (map != null) {
                Object expireTime = map.get("expireTime");
                if (expireTime != null) {
                    LocalDateTime endTime = ((Date)expireTime).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                    response.setEndTime(endTime);
                }
                Object mealType = map.get("mealType");
                if (mealType != null) {
                    response.setMealType((Integer)mealType);
                }
            }

            /*ZfbMonitorOrder zfbMonitorOrder = zfbMonitorOrderMapper.selectOne(new LambdaQueryWrapper<ZfbMonitorOrder>()
                    .eq(ZfbMonitorOrder::getOrderStatus, 1)
                    .eq(ZfbMonitorOrder::getMerchantId, systemAdmin.getMerId())
                    .orderByDesc(ZfbMonitorOrder::getId).last("limit 1"));

            if (ObjectUtil.isNotNull(zfbMonitorOrder)) {
                ZfbMonitorTrafficSetMeal monitorTrafficSetMeal = zfbMonitorTrafficSetMealMapper.selectById(zfbMonitorOrder.getProductId());

                if (ObjectUtil.isNotNull(monitorTrafficSetMeal)) {
                    ZfbEquipmentOrderResponse zfbEquipmentOrderResponse = new ZfbEquipmentOrderResponse();
                    zfbEquipmentOrderResponse.setOrderNo(zfbMonitorOrder.getOrderNo());
                    zfbEquipmentOrderResponse.setProductName(monitorTrafficSetMeal.getName());

                    zfbEquipmentOrderResponse.setCreateTime(zfbMonitorOrder.getCreateTime());
                    // 类型 1=月 2=季 3=年
                    zfbEquipmentOrderResponse.setProductType(monitorTrafficSetMeal.getType());
                    if (monitorTrafficSetMeal.getType() == 1) {
                        LocalDateTime localDateTime = zfbMonitorOrder.getCreateTime().plusDays(30);
                        zfbEquipmentOrderResponse.setEndTime(localDateTime);
                    }
                    if (monitorTrafficSetMeal.getType() == 2) {
                        LocalDateTime localDateTime = zfbMonitorOrder.getCreateTime().plusDays(90);
                        zfbEquipmentOrderResponse.setEndTime(localDateTime);
                    }
                    if (monitorTrafficSetMeal.getType() == 3) {
                        LocalDateTime localDateTime = zfbMonitorOrder.getCreateTime().plusYears(1);
                        zfbEquipmentOrderResponse.setEndTime(localDateTime);
                    }

                    response.setOrder(zfbEquipmentOrderResponse);
                    response.setEndTime(zfbEquipmentOrderResponse.getEndTime());
                }
            }*/


            // 免费时长 1=免费一个月 2=免费一个季度 3=免费一年 4=免费两年  5=免费三年
            /*Integer freeMonitorTime = merchant.getFreeMonitorTime();
            Integer monitorType = merchant.getMonitorType();
            if (ObjectUtil.isNotNull(freeMonitorTime)
                    && StrUtil.isNotBlank(merchant.getMonitorStartTime())
                    && freeMonitorTime == 1) {
                String monitorStartTimeStr = merchant.getMonitorStartTime();
                // 解析时间字符串到 LocalDateTime
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime monitorStartTime = LocalDateTime.parse(monitorStartTimeStr, formatter);

                LocalDateTime localDateTime = monitorStartTime.plusDays(30);
                response.setEndTime(localDateTime);
            }
            if (ObjectUtil.isNotNull(freeMonitorTime)
                    && StrUtil.isNotBlank(merchant.getMonitorStartTime())
                    && freeMonitorTime == 2) {
                String monitorStartTimeStr = merchant.getMonitorStartTime();
                // 解析时间字符串到 LocalDateTime
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime monitorStartTime = LocalDateTime.parse(monitorStartTimeStr, formatter);
                LocalDateTime localDateTime = monitorStartTime.plusDays(90);
                response.setEndTime(localDateTime);
            }
            if (ObjectUtil.isNotNull(freeMonitorTime)
                    && StrUtil.isNotBlank(merchant.getMonitorStartTime())
                    && freeMonitorTime == 3) {
                String monitorStartTimeStr = merchant.getMonitorStartTime();
                // 解析时间字符串到 LocalDateTime
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime monitorStartTime = LocalDateTime.parse(monitorStartTimeStr, formatter);
                LocalDateTime localDateTime = monitorStartTime.plusYears(1);
                response.setEndTime(localDateTime);
            }
            if (ObjectUtil.isNotNull(freeMonitorTime)
                    && StrUtil.isNotBlank(merchant.getMonitorStartTime())
                    && freeMonitorTime == 4) {
                String monitorStartTimeStr = merchant.getMonitorStartTime();
                // 解析时间字符串到 LocalDateTime
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime monitorStartTime = LocalDateTime.parse(monitorStartTimeStr, formatter);
                LocalDateTime localDateTime = monitorStartTime.plusYears(2);
                response.setEndTime(localDateTime);
            }
            if (ObjectUtil.isNotNull(freeMonitorTime)
                    && StrUtil.isNotBlank(merchant.getMonitorStartTime())
                    && freeMonitorTime == 5) {
                String monitorStartTimeStr = merchant.getMonitorStartTime();
                // 解析时间字符串到 LocalDateTime
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime monitorStartTime = LocalDateTime.parse(monitorStartTimeStr, formatter);

                LocalDateTime localDateTime = monitorStartTime.plusYears(5);
                response.setEndTime(localDateTime);
            }*/


        });

        return commonPage;
    }

    /**
     * 绑定商品
     *
     * @param bindProductRequest
     * @return
     */
    @Override
    public boolean merchantBindProduct(ZfbMonitorEquipmentBindProductReq bindProductRequest, SystemAdmin systemAdmin) {
        log.info("#merchantBindProduct#绑定商品:{}", JSON.toJSONString(bindProductRequest));

        Product product = productDao.selectById(bindProductRequest.getProductId());
        if (ObjectUtil.isNull(product)) {
            throw new AppException("商品不存在");
        }
        if (!Objects.equals(systemAdmin.getMerId(), product.getMerId())) {
            throw new AppException("非当前商户商品");
        }

        List<ZfbMonitorEquipment> monitorEquipmentList = zfbMonitorEquipmentMapper.selectList(new LambdaQueryWrapper<ZfbMonitorEquipment>()
                .in(ZfbMonitorEquipment::getLicense, bindProductRequest.getLicense()));
        if (CollectionUtils.isEmpty(monitorEquipmentList) || monitorEquipmentList.size() != bindProductRequest.getLicense().size()) {
            log.info("#merchantBindProduct#bindProductRequest如参={}", JSON.toJSONString(bindProductRequest));
            throw new AppException("设备不存在");
        }
        monitorEquipmentList.forEach(monitorEquipment -> {
            if (!Objects.equals(systemAdmin.getMerId(), monitorEquipment.getMerchantId())) {
                throw new AppException("非当前用户设备，无法绑定");
            }
        });

        String license = Joiner.on(",").join(bindProductRequest.getLicense());
        product.setLicense(license);
        product.setUpdateTime(DateTime.now());
        return productDao.updateById(product) > 0;
    }

    /**
     * 唤醒设备
     *
     * @param license
     * @return
     */
    @Override
    public boolean wakeUpEquipment(String license) {
        ZfbMonitorEquipment monitorEquipment = checkExitQuipment(license);
        boolean res = monitorChannelHandle.wakeUpEquipment(license, monitorEquipment.getEquipmentType());
        return res;
    }
    /**
     * 唤醒设备
     *
     * @param license
     * @return
     */
    @Override
    public boolean wakeUpEquipment(String[] license) {
        log.info("#wakeUpEquipment#license唤醒设备=[{}]", JSON.toJSONString(license));
        List<ZfbMonitorEquipment> monitorEquipmentList = checkExitQuipment(license);
        boolean overallResult = true;
        for (ZfbMonitorEquipment monitorEquipment : monitorEquipmentList) {
            try {
                boolean res = monitorChannelHandle.wakeUpEquipment(monitorEquipment.getLicense(), monitorEquipment.getEquipmentType());
                if (!res) {
                    overallResult = false;
                    log.warn("设备 {} 唤醒失败", monitorEquipment.getLicense());
                }
            } catch (Exception e) {
                overallResult = false;
                log.error("设备 {} 唤醒失败", monitorEquipment.getLicense(), e);
            }
        }
        return overallResult;
    }

    /**
     * 唤醒设备，并返回唤醒失败的设备license列表
     * @param license
     * @return
     */
    @Override
    public List<String> wakeUpEquipmentOptimized(String[] license) {
        log.info("#wakeUpEquipmentOptimized#license唤醒设备=[{}]", JSON.toJSONString(license));
        List<ZfbMonitorEquipment> zfbMonitorEquipments = checkExitQuipmentOptimized(license);
        List<String> failLicenses = new ArrayList<>();
        for (ZfbMonitorEquipment zfbMonitorEquipment : zfbMonitorEquipments) {
            try {
                boolean res = monitorChannelHandle.wakeUpEquipment(zfbMonitorEquipment.getLicense(), zfbMonitorEquipment.getEquipmentType());
                if (!res) {
                    failLicenses.add(zfbMonitorEquipment.getLicense());
                    log.error("设备 {} 唤醒失败", zfbMonitorEquipment.getLicense());
                }
            } catch (Exception e) {
                failLicenses.add(zfbMonitorEquipment.getLicense());
                log.error("设备 {} 唤醒失败", zfbMonitorEquipment.getLicense(), e);
            }
        }

        return failLicenses;
    }

    /**
     * 校验是否存在该设备
     *
     * @param license
     * @return
     */
    private List<ZfbMonitorEquipment> checkExitQuipment(String []license) {
        List<ZfbMonitorEquipment> monitorEquipment = zfbMonitorEquipmentMapper.selectList(new LambdaQueryWrapper<ZfbMonitorEquipment>()
                .select(ZfbMonitorEquipment::getLicense, ZfbMonitorEquipment::getEquipmentType)
                .in(ZfbMonitorEquipment::getLicense, license));
        if (ObjectUtil.isNull(monitorEquipment) || monitorEquipment.isEmpty()) {
            throw new AppException("不存在该设备");
        }
        return monitorEquipment;
    }

    /**
     * 校验是否存在该设备（优化版）
     *
     * @param license
     * @return
     */
    private List<ZfbMonitorEquipment> checkExitQuipmentOptimized(String []license) {
        List<ZfbMonitorEquipment> monitorEquipment = zfbMonitorEquipmentMapper.selectList(new LambdaQueryWrapper<ZfbMonitorEquipment>()
                .select(ZfbMonitorEquipment::getLicense, ZfbMonitorEquipment::getEquipmentType)
                .in(ZfbMonitorEquipment::getLicense, license));
        if (ObjectUtil.isNull(monitorEquipment) || CollectionUtils.isEmpty(monitorEquipment)) {
            throw new AppException("不存在该设备");
        }
        return monitorEquipment;
    }

    /**
     * 校验是否存在该设备
     *
     * @param license
     * @return
     */
    private ZfbMonitorEquipment checkExitQuipment(String license) {
        ZfbMonitorEquipment monitorEquipment = zfbMonitorEquipmentMapper.selectOne(new LambdaQueryWrapper<ZfbMonitorEquipment>()
                .select(ZfbMonitorEquipment::getLicense, ZfbMonitorEquipment::getEquipmentType)
                .eq(ZfbMonitorEquipment::getLicense, license).last("limit 1"));
        if (ObjectUtil.isNull(monitorEquipment)) {
            throw new AppException("不存在该设备");
        }
        return monitorEquipment;
    }


    /**
     * 查询设备状态
     *
     * @param license
     * @return
     */
    @Override
    public MonitorChannelEquipmentStatusVo getEquipmentStatus(String license) {
        ZfbMonitorEquipment monitorEquipment = this.checkExitQuipment(license);
        MonitorChannelEquipmentStatusVo equipmentStatus = monitorChannelHandle.getEquipmentStatus(license, monitorEquipment.getEquipmentType());
        return equipmentStatus;
    }


    /**
     * 查询设备流媒体地址
     *
     * @param license
     * @return
     */
    @Override
    public MonitorChannelMediaAddressVo getMediaAddress(String license) {
        //校验license设备是否存在
        ZfbMonitorEquipment monitorEquipment = this.checkExitQuipment(license);

        MonitorChannelMediaAddressVo addressVo = monitorChannelHandle.getMediaAddress(license, monitorEquipment.getEquipmentType());
        return addressVo;
    }

    /**
     * ptz控制设备
     *
     * @param ctrlPTZRequestVo
     * @return
     */
    @Override
    public boolean ctrlPTZ(CtrlPTZRequestVo ctrlPTZRequestVo) {
        //校验是否存在该设备
        ZfbMonitorEquipment monitorEquipment = checkExitQuipment(ctrlPTZRequestVo.getLicense());

        boolean res = monitorChannelHandle.ctrlPTZ(ctrlPTZRequestVo, monitorEquipment.getEquipmentType());
        return res;
    }

    /**
     * 通过该命令向设备设置时间信息
     *
     * @param setTimeRequestVo
     * @returnD
     */
    @Override
    public boolean setTime(MonitorSetTimeRequestVo setTimeRequestVo) {
        //校验是否存在该设备
        ZfbMonitorEquipment monitorEquipment = checkExitQuipment(setTimeRequestVo.getLicense());

        boolean res = monitorChannelHandle.setTime(setTimeRequestVo, monitorEquipment.getEquipmentType());
        return res;
    }


    /**
     * 通知设备进⾏行行物理理变焦
     * 鹤梦云-2.6.2.8.6 通知设备进⾏行行物理理变焦
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo setAdjustFocalLength(AdjustFocalLengthRequestVo requestVo) {
        //校验是否存在该设备
        ZfbMonitorEquipment monitorEquipment = checkExitQuipment(requestVo.getLicense());
        ThirdMonitorResultVo resultVo = monitorChannelHandle.setAdjustFocalLength(requestVo, monitorEquipment.getEquipmentType());
        return resultVo;
    }


    /**
     * 通知设备抓图
     * 鹤梦云-4.6.2.2.8 通知设备抓图
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo noticeDeviceUploadPicRequest(NoticeDeviceUploadPicRequestVo requestVo) {
        //校验是否存在该设备
        ZfbMonitorEquipment monitorEquipment = checkExitQuipment(requestVo.getLicense());
        ThirdMonitorResultVo resultVo = monitorChannelHandle.noticeDeviceUploadPicRequest(requestVo, monitorEquipment.getEquipmentType());
        return resultVo;
    }


    /**
     * 查询设备云端录像⽇日历
     * 4.6.2.3.1 查询设备云端录像⽇日历
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo<VideoQueryCalendarResultVo> getVideoQueryCalendar(VideoQueryCalendarRequestVo requestVo) {
        //校验是否存在该设备
        ZfbMonitorEquipment monitorEquipment = checkExitQuipment(requestVo.getLicense());
        ThirdMonitorResultVo resultVo = monitorChannelHandle.getVideoQueryCalendar(requestVo, monitorEquipment.getEquipmentType());

        return resultVo;
    }


    /**
     * 查询设备云端录像列列表
     * 4.6.2.3.2 查询设备云端录像列列表
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo<VideoQueryListResultVo> getVideoQueryList(VideoQueryListRequestVo requestVo) {
        //校验是否存在该设备
        ZfbMonitorEquipment monitorEquipment = checkExitQuipment(requestVo.getLicense());
        ThirdMonitorResultVo resultVo = monitorChannelHandle.getVideoQueryList(requestVo, monitorEquipment.getEquipmentType());

        return resultVo;
    }

    /**
     * 查询设备云端录像详情
     * 4.6.2.3.3 查询设备云端录像详情
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo<VideoQueryDetailResultVo> getVideoQueryDetail(VideoQueryDetailRequestVo requestVo) {
        //校验是否存在该设备
        ZfbMonitorEquipment monitorEquipment = checkExitQuipment(requestVo.getLicense());
        ThirdMonitorResultVo resultVo = monitorChannelHandle.getVideoQueryDetail(requestVo, monitorEquipment.getEquipmentType());

        return resultVo;
    }


    /**
     * 查询设备云端图⽚片列列表
     * 4.6.2.2.2 查询设备云端图⽚片列列表
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo<PictureQueryListResultVo> getPictureQueryList(VideoQueryListRequestVo requestVo) {
        //校验是否存在该设备
        ZfbMonitorEquipment monitorEquipment = checkExitQuipment(requestVo.getLicense());
        ThirdMonitorResultVo resultVo = monitorChannelHandle.getPictureQueryList(requestVo, monitorEquipment.getEquipmentType());

        return resultVo;
    }


    /**
     * 查询设备云端图⽚片详情
     * 4.6.2.2.3 查询设备云端图⽚片详情
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo<PictureQueryDetailResultVo> getPictureQueryDetail(PictureQueryDetailRequestVo requestVo) {
        //校验是否存在该设备
        ZfbMonitorEquipment monitorEquipment = checkExitQuipment(requestVo.getLicense());
        ThirdMonitorResultVo resultVo = monitorChannelHandle.getPictureQueryDetail(requestVo, monitorEquipment.getEquipmentType());

        return resultVo;
    }


    /**
     * 查询设备云端图⽚片详情
     * 鹤梦云-4.6.2.2.7 查询设备本地图⽚片列列表(须设备在线才可查询)
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo<GetLocalPicListResultVo> getGetLocalPicList(VideoQueryListRequestVo requestVo) {
        //校验是否存在该设备
        ZfbMonitorEquipment monitorEquipment = checkExitQuipment(requestVo.getLicense());
        ThirdMonitorResultVo resultVo = monitorChannelHandle.getGetLocalPicList(requestVo, monitorEquipment.getEquipmentType());
        return resultVo;
    }


    /**
     * 查询设备本地录像列列表
     * 鹤梦云-4.6.2.3.5 查询设备本地录像列列表
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo<GetLocalFileListResultVo> getLocalFileList(GetLocalFileListRequestVo requestVo) {
        //校验是否存在该设备
        ZfbMonitorEquipment monitorEquipment = checkExitQuipment(requestVo.getLicense());
        ThirdMonitorResultVo resultVo = monitorChannelHandle.getLocalFileList(requestVo, monitorEquipment.getEquipmentType());
        return resultVo;
    }


    /**
     * 鹤梦云-4.6.2.2.5 根据事件时间查询设备云端图⽚片详情
     */
    @Override
    public ThirdMonitorResultVo<PictureQueryDetailByTimeResultVo> QueryDetailByTime(QueryDetailByTimeRequestVo requestVo) {
        //获取监控渠道
        ZfbMonitorEquipment monitorEquipment = this.checkExitQuipment(requestVo.getLicense());
        ThirdMonitorResultVo resultVo = monitorChannelHandle.QueryDetailByTime(requestVo, monitorEquipment.getEquipmentType());

        return resultVo;
    }


    /**
     * 4.5.1 根据产品ID进⾏行行订阅数据
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo subscribe(MonitorSubscribeRequestVo requestVo) {
        //获取监控渠道
        ZfbMonitorEquipment monitorEquipment = this.checkExitQuipment(requestVo.getLicense());
        ThirdMonitorResultVo resultVo = monitorChannelHandle.subscribe(requestVo, monitorEquipment.getEquipmentType());
        return resultVo;
    }

    @Override
    public List<ZfbMonitorEquipment> getMonitorLicense(List<String> licenseList) {
        List<ZfbMonitorEquipment> zfbMonitorEquipments = zfbMonitorEquipmentMapper.selectList(new LambdaQueryWrapper<ZfbMonitorEquipment>()
                .in(ZfbMonitorEquipment::getLicense, licenseList));

        return zfbMonitorEquipments;
    }


    /**
     * 4.6.2.6.3 摄像头开关
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo setOpenFlag(MonitorSetOpenFlagVo requestVo) {
        //获取监控渠道
        ZfbMonitorEquipment monitorEquipment = this.checkExitQuipment(requestVo.getLicense());
        ThirdMonitorResultVo resultVo = monitorChannelHandle.setOpenFlag(requestVo, monitorEquipment.getEquipmentType());
        return resultVo;

    }

    /**
     * 4.6.2.3.4 查询设备本地录像⽇日历
     *
     * @param requestVo
     * @return
     */
    @Override
    public ThirdMonitorResultVo getLocalFileCalendar(GetLocalFileCalendarVo requestVo) {

        //获取监控渠道
        ZfbMonitorEquipment monitorEquipment = this.checkExitQuipment(requestVo.getLicense());
        ThirdMonitorResultVo resultVo = monitorChannelHandle.getLocalFileCalendar(requestVo, monitorEquipment.getEquipmentType());
        return resultVo;
    }

    /**
     * 获取v3版本的 accessToken
     *
     * @return
     */
    public String getV3AccessToken() {
        return monitorChannelHandle.getV3AccessToken(0);
    }

    /**
     * 5.5.8.2 获取 TF 录像回放地址标准流地址
     * 功能说明：
     * 1、获取设备流媒体录像回放地址；
     * 2、请求路径 url: /GMModule/V3/Media/GetMultiMediaRecordAddr；
     *
     * @param requestVo
     * @return
     */
    public GetMultiMediaRecordAddrV3Response GetMultiMediaRecordAddr(GetMultiMediaRecordAddrV3Request requestVo, Integer equipmentType) {
        return monitorChannelHandle.GetMultiMediaRecordAddr(requestVo, equipmentType);
    }


    /**
     * 5.5.3.2 查询 TF 卡录像列表
     * 功能说明：
     * 1、按照日期查询 TF 卡录像列表；
     * 2、请求 URL；/GMModule/V3/Device/GetLocalFileList；
     *
     * @param requestVo
     * @return
     */
    public GetLocalFileListV3Response GetLocalFileList(GetLocalFileListV3Request requestVo, Integer equipmentType) {
        return monitorChannelHandle.GetLocalFileList(requestVo, equipmentType);

    }


    /**
     * 5.5.3.3 查询 TF 卡事件日历
     * 功能说明：
     * 1、查询 TF 卡那天存在报警事件；
     * 2、请求 URL；/GMModule/V3/Device/GetLocalEventCalendar
     *
     * @param requestVo
     * @return
     */
    public GetLocalEventCalendarV3Response GetLocalEventCalendar(GetLocalEventCalendarV3Request requestVo, Integer equipmentType) {
        return monitorChannelHandle.GetLocalEventCalendar(requestVo, equipmentType);

    }


    /**
     * 5.2.2 用户账号添加/删除设备
     * 功能说明：
     * 1、用户添加或者删除设备；
     * 2、该接口影响用户对设备的所有操作;
     * 3、请求路径 url: /GMModule/SetDevices;
     *
     * @param requestVo
     * @return
     */
    public SetDevicesV3Response SetDevices(SetDevicesV3Request requestVo, Integer equipmentType) {
        return monitorChannelHandle.SetDevices(requestVo, equipmentType);
    }


    /**
     * 5.5.1.1 查询设备的业务配置
     * 功能说明：
     * 1、根据功能模块类型查询设备的配置和能力；
     * 2、请求 URL；/GMModule/V3/Device/GetDeviceModel;
     *
     * @param requestVo
     * @return
     */
    public JSONObject GetDeviceModel(GetDeviceModelV3Request requestVo, Integer equipmentType) {
        return monitorChannelHandle.GetDeviceModel(requestVo, equipmentType);
    }

    /**
     * 5.5.8.1 获取直播播放地址
     * 功能说明：
     * 1、获取设备流媒体直播地址；
     * 2、请求路径 url: /GMModule/V3/Media/GetMultiMediaAddr；
     *
     * @param requestVo
     * @return
     */
    @Override
    public GetMultiMediaAddrV3Response GetMultiMediaAddr(GetMultiMediaAddrV3Request requestVo, Integer equipmentType) {
        return monitorChannelHandle.GetMultiMediaAddr(requestVo, equipmentType);
    }


    /**
     * 5.5.8.2获取TF录像回放地址标准流地址
     * 1、获取设备流媒体录像回放地址；
     * 2、请求路径url:/GMModule/V3/Media/GetMultiMediaRecordAddr；
     *
     * @param request
     * @return
     */
    @Override
    public GetMultiMediaAddrV3Response GetMultiMediaRecordV3Request(GetMultiMediaRecordV3Request request, Integer equipmentType) {
        return monitorChannelHandle.GetMultiMediaRecordV3Request(request, equipmentType);
    }

    /**
     * 5.5.4.7 摄像机开关
     * 功能说明：
     * 1、关闭摄像机后，停止所有录制，同时app默认不可以观看，同时镜头转向隐私位；
     * 2、请求URL；/GMModule/V3/Device/SetOpenFlag
     *
     * @param requestVo
     * @return
     */
    @Override
    public JSONObject v3SetOpenFlag(MonitorSetOpenFlagVo requestVo, Integer equipmentType) {
        return monitorChannelHandle.v3SetOpenFlag(requestVo, equipmentType);
    }

    /*@Override
    public PageInfo<ZfbMonitorEquipment> getAdminPage(ZfbMonitorEquipmentRequest pageParamRequest) {
        // 1. 先查询所有设备（不限制数量）
        List<ZfbMonitorEquipment> allDevices = zfbMonitorEquipmentMapper.selectList(new LambdaQueryWrapper<>());

        // 2. 处理设备在线状态并过滤
        List<ZfbMonitorEquipment> onlineDevices = allDevices.stream()
                .peek(device -> {
                    MonitorChannelEquipmentStatusVo status = isDeviceOnline(device.getLicense());
                    if (status != null && !"2".equals(status.getStatus())) {
                        device.setChannelEquipmentStatusVo(status);
                        MonitorChannelMediaAddressVo mediaAddress = monitorChannelHandle.getMediaAddress(
                                device.getLicense(), device.getEquipmentType());
                        device.setMonitorMediaAddressList(Arrays.asList(mediaAddress));
                    }
                })
                .filter(device ->
                        device.getChannelEquipmentStatusVo() != null &&
                                device.getMonitorMediaAddressList() != null)
                .collect(Collectors.toList());
        // 3. 内存分页计算
        int pageSize = pageParamRequest.getLimit();
        int total = onlineDevices.size();
        int totalPage = (total + pageSize - 1) / pageSize;

        int fromIndex = (pageParamRequest.getPage() - 1) * pageSize;
        int toIndex = Math.min(fromIndex + pageSize, total);

        List<ZfbMonitorEquipment> pageList = onlineDevices.subList(fromIndex, toIndex);

        // 4. 构造分页对象
        Page<ZfbMonitorEquipment> page = new Page<>(pageParamRequest.getPage(), pageSize);
        page.setRecords(pageList);
        page.setTotal(total);
        page.setPages(totalPage);

        return new PageInfo<>(page.getRecords());
    }*/
    /**
     * 根据前端条件查询设备列表
     * @param searchRequest
     * @return
     */
    @Override
    public PageInfo<ZfbMonitorEquipment> getEquipmentListByCondition(ZfbMonitorEquipmentCondition searchRequest) {
        LambdaQueryWrapper<ZfbMonitorEquipment> lqw = createEquipmentQueryCondition(searchRequest);
        com.github.pagehelper.Page<ZfbMonitorEquipment> page = PageHelper.startPage(searchRequest.getPage(), searchRequest.getLimit());
        List<ZfbMonitorEquipment> batch = zfbMonitorEquipmentMapper.selectList(lqw);

        for (ZfbMonitorEquipment device : batch) {
            // 补充媒体地址
            MonitorChannelMediaAddressVo mediaAddress = monitorChannelHandle.getMediaAddress(
                    device.getLicense(), device.getEquipmentType());
            device.setMonitorMediaAddressList(Arrays.asList(mediaAddress));
            Merchant merchant = merchantService.getById(device.getMerchantId());
            List<ProMerchantProductResponse> merchantProductResponseList = productService.getRecommendedProductsByMerId(merchant.getId(), 6);
            device.setProList(merchantProductResponseList);
            device.setMerchantInfo(merchant);
            if (merchant.getBrandId() != null && merchant.getBrandId() > 0) {
                SystemAdmin systemAdmin = systemAdminService.getById(merchant.getBrandId());
                if (systemAdmin.getBrandId() != null && systemAdmin.getBrandId() > 0) {
                    Brand brand = brandService.getById(systemAdmin.getBrandId());
                    device.setBrand(brand);
                }
            }
        }

        return CommonPage.copyPageInfo(page, batch);
    }

    @Override
    public List<ZfbMonitorEquipment> getLicenseList(Integer id) {
        LambdaQueryWrapper<ZfbMonitorEquipment> lqw = Wrappers.lambdaQuery();
        lqw.eq(ZfbMonitorEquipment::getMerchantId, id);
        lqw.orderByAsc(ZfbMonitorEquipment::getCreateTime);
        return list(lqw);
    }

    /**
     * 当前订单关联的监控列表
     * @param orderNo
     * @return
     */
    @Override
    public ZfbOrderMonitorLinkDataResponse getOrderMonitorLink(String orderNo) {
        List<OrderDetail> orderDetailList = orderDetailService.getByOrderNo(orderNo);
        Integer productId = orderDetailList.get(0).getProductId();

        Product product = productService.getById(productId);
        if (StrUtil.isBlank(product.getLicense())) {
            return new ZfbOrderMonitorLinkDataResponse();
        }
        List<String> licenseList = Arrays.asList(product.getLicense().split(","));
        if (CollUtil.isEmpty(licenseList)) {
            return new ZfbOrderMonitorLinkDataResponse();
        }

        ZfbOrderMonitorLinkDataResponse response = new ZfbOrderMonitorLinkDataResponse();

        // 查询普通商品
        licenseList.removeIf(o-> StrUtil.isBlank(o));
        response.setLicenseList(licenseList);

        // 获取绑定关系
        List<ZfbMonitorDeviceBind> bindList = zfbMonitorDeviceBindService.getListInLicense(licenseList, -1);
        ZfbMonitorDeviceBind latest = getLatestActiveTime(bindList);

        List<MonitorChannelMediaAddressVo> mediaAddressList = Lists.newArrayList();
        licenseList.forEach(license -> {
            ZfbMonitorEquipment monitorEquipment = zfbMonitorEquipmentService.getOne(new LambdaQueryWrapper<ZfbMonitorEquipment>().eq(ZfbMonitorEquipment::getLicense,license));
            if (ObjectUtil.isNotNull(monitorEquipment)) {
                MonitorChannelMediaAddressVo mediaAddress = monitorChannelHandle.getMediaAddress(monitorEquipment.getLicense(), monitorEquipment.getEquipmentType());
                mediaAddressList.add(mediaAddress);
            }
        });
        response.setMonitorMediaAddressList(mediaAddressList);
        // 排序
        sortMonitor(response, latest);
        return response;
    }

    private void sortMonitor(ZfbOrderMonitorLinkDataResponse response, ZfbMonitorDeviceBind latest) {
        if (ObjectUtil.isNull(latest)) {
            return;
        }
        if (CollUtil.isEmpty(response.getLicenseList())) {
            return;
        }
        if (CollUtil.isEmpty(response.getMonitorMediaAddressList())) {
            return;
        }
        int i = response.getLicenseList().indexOf(latest.getLicense());
        if (i != -1) {
            response.setLicenseList(moveItemToFront(response.getLicenseList(), latest.getLicense()));
            MonitorChannelMediaAddressVo monitorChannelMediaAddressVo = response.getMonitorMediaAddressList().get(i);
            response.getMonitorMediaAddressList().remove(i);
            response.getMonitorMediaAddressList().add(0, monitorChannelMediaAddressVo);
        }
    }
    public static List<String> moveItemToFront(List<String> list, String target) {
        List<String> newList = new ArrayList<>();
        if (list.contains(target)) {
            newList.add(target);
        }
        for (String s : list) {
            if (!s.equals(target)) {
                newList.add(s);
            }
        }
        return newList;
    }

    private ZfbMonitorDeviceBind getLatestActiveTime(List<ZfbMonitorDeviceBind> bindList) {
        if (CollUtil.isEmpty(bindList)) {
            return null;
        }
        Date now = DateUtil.date();
        Optional<ZfbMonitorDeviceBind> max = bindList.stream().filter(x -> {
            // 判断 inputDate 是否在最近 10 分钟内
            boolean isInHalfHour = x.getLatestActiveTime() != null && DateUtil.between(now, x.getLatestActiveTime(), DateUnit.MINUTE) <= minute
                    && !x.getLatestActiveTime().after(now);  // 确保不是未来时间
            return isInHalfHour;
        }).max(Comparator.comparing(ZfbMonitorDeviceBind::getLatestActiveTime));
        if (ObjectUtil.isNotNull(max) && max.isPresent()) {
            return max.get();
        }
        return null;
    }

    @Override
    public ZfbMonitorControlLightResponse controlLight(MonitorControlLightRequest request, String orderNo) {
        // 检查监控是否有人在查看，有查看的直接返回
        ZfbMonitorLightUserInfoResponse res = checkMonitorViewUser(request, orderNo);
        if (res.getIsView() && !res.getNickname().equals(request.getCurOrderUser())) {
            throw new AppException(CommonResultCode.VALIDATE_FAILED.setMessage("“" + res.getNickname() + "”正在查看监控"));
        }
        ZfbMonitorControlLightResponse response = new ZfbMonitorControlLightResponse();
        // 获取可重入锁对象
        RLock lock = redissonClient.getLock("lock:monitor:" + request.getLicense());
        try {
            // 尝试获取锁，等待时间为10秒，锁自动释放时间为30秒
            boolean isLocked = lock.tryLock(10, 30, TimeUnit.SECONDS);
            if (isLocked) {
                res = checkMonitorViewUser(request, orderNo);
                if (res.getIsView() && !res.getNickname().equals(request.getCurOrderUser())) {
                    throw new AppException(CommonResultCode.VALIDATE_FAILED.setMessage("“" + res.getNickname() + "”正在查看监控"));
                }
                try {
                    String userKey = "monitor:" + request.getLicense() + ":view-user";
                    redisUtil.set(userKey, request.getCurOrderUser(), 60l, TimeUnit.SECONDS);

                    Order order = orderService.getByOrderNo(orderNo);
                    Merchant merchant = merchantService.getById(order.getMerId());
                    // 可优化
                    ZfbMonitorEquipment monitorEquipment = zfbMonitorEquipmentService.getOne(new LambdaQueryWrapper<ZfbMonitorEquipment>()
                            .select(ZfbMonitorEquipment::getId)
                            .eq(ZfbMonitorEquipment::getLicense, request.getLicense())
                            .eq(ZfbMonitorEquipment::getMerchantId, merchant.getId())
                    );
                    if (ObjectUtil.isNull(monitorEquipment)) {
                        throw new AppException(CommonResultCode.VALIDATE_FAILED.setMessage("查询不到监控设备"));
                    }
                    ZfbMonitorDeviceBind bind = zfbMonitorDeviceBindService.getOne(new LambdaQueryWrapper<ZfbMonitorDeviceBind>()
                            .select(ZfbMonitorDeviceBind::getDeviceId)
                            .eq(ZfbMonitorDeviceBind::getMeid, monitorEquipment.getId())
                            .eq(ZfbMonitorDeviceBind::getIsDeleted, false)
                    );
                    if (ObjectUtil.isNull(bind)) {
                        throw new AppException(CommonResultCode.VALIDATE_FAILED.setMessage("查询不到绑定网关"));
                    }

                    Device device = deviceService.getById(bind.getDeviceId());
                    String imei = device.getImei();

                    String resKey = "monitor:" + imei + ":" + request.getDeviceMac() + ":status:res";
                    redisUtil.delete(resKey);

                    Map<String, Object> param = new HashMap<>();
                    param.put("license", request.getLicense());
                    param.put("orderNo", orderNo);
                    param.put("now", DateUtil.now());

                    String key = "monitor:" + request.getLicense() + ":send";
                    // 检查是否重复发送
                    Object statusObj = redisUtil.get(key);
                    if (ObjectUtil.isNotNull(statusObj)) {
                        response.setStatus(1);
                        response.setRes("获取" + statusObj + "结果中，请稍后");
                        return response;
                    }

                    try {
                        mqttConfigService.publishControlCmd(request);
                    } catch (Exception e) {
                        e.printStackTrace();
                        throw new AppException(CommonResultCode.VALIDATE_FAILED.setMessage("消息服务异常"));
                    }
                    redisUtil.set(key, request.getDeviceMac(), 60l, TimeUnit.SECONDS);
                    // 当前亮灯的用户
                    LambdaQueryWrapper<MerchantOrder> lqw = Wrappers.lambdaQuery();
                    lqw.eq(MerchantOrder::getOrderNo, orderNo);
                    lqw.last("limit 1");
                    MerchantOrder one = merchantOrderService.getOne(lqw);
                    redisUtil.set(userKey, one.getRealName(), 60l, TimeUnit.SECONDS);

                    response.setStatus(0);

                } finally {
                    // 释放锁
                    lock.unlock();
                }
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("Failed to acquire lock");
        }

        return response;
    }

    private ZfbMonitorLightUserInfoResponse checkMonitorViewUser(MonitorControlLightRequest request, String orderNo) {
        ZfbMonitorLightUserInfoResponse response = new ZfbMonitorLightUserInfoResponse();
        response.setIsView(false);
        String userKey = "monitor:" + request.getLicense().trim() + ":view-user";
        Object o = redisUtil.get(userKey);
        if (ObjectUtil.isNotNull(o)) {
            response.setNickname(o.toString());
//            LambdaQueryWrapper<MerchantOrder> lqw = Wrappers.lambdaQuery();
//            lqw.eq(MerchantOrder::getOrderNo, orderNo);
//            lqw.last("limit 1");
//            MerchantOrder one = merchantOrderService.getOne(lqw);
//            if (!o.toString().equals(request.getCurOrderUser())) {
                response.setIsView(true);
////                return false;
//            }
        }
        return response;
    }

    /**
     * 获取10分钟内被唤醒的设备
     * @param bindList
     * @return
     */
    private List<ZfbMonitorDeviceBind> getLatestActiveTimeList(List<ZfbMonitorDeviceBind> bindList) {
        if (CollUtil.isEmpty(bindList)) {
            return null;
        }
        Date now = DateUtil.date();
        List<ZfbMonitorDeviceBind> collect = bindList.stream().filter(x -> {
            // 判断 inputDate 是否在最近 10 分钟内
            boolean isInHalfHour = x.getLatestActiveTime() != null && DateUtil.between(now, x.getLatestActiveTime(), DateUnit.MINUTE) <= minute
                    && !x.getLatestActiveTime().after(now);  // 确保不是未来时间
            return isInHalfHour;
        }).collect(Collectors.toList());
        return collect;
    }

    private LambdaQueryWrapper<ZfbMonitorEquipment> createEquipmentQueryCondition(ZfbMonitorEquipmentCondition searchRequest) {
        LambdaQueryWrapper<ZfbMonitorEquipment> lqw = Wrappers.lambdaQuery();
        if (StrUtil.isNotBlank(searchRequest.getLicense())) {
            lqw.eq(ZfbMonitorEquipment::getLicense, searchRequest.getLicense());
        }
        if (ObjectUtil.isNotNull(searchRequest.getBrandId()) && searchRequest.getBrandId() > 0) {
            SystemAdmin systemAdmin = systemAdminService.getOne(
                    new LambdaQueryWrapper<SystemAdmin>()
                            .eq(SystemAdmin::getBrandId, searchRequest.getBrandId()));
            if (ObjectUtil.isNotNull(systemAdmin) && systemAdmin.getId() > 0) {
                List<Integer> merchantIdList = merchantService.list(new LambdaQueryWrapper<Merchant>()
                                .eq(Merchant::getBrandId, systemAdmin.getId())
                                .select(Merchant::getId))
                        .stream()
                        .map(Merchant::getId)
                        .collect(Collectors.toList());
                if (merchantIdList != null && merchantIdList.size() > 0) {
                    lqw.in(ZfbMonitorEquipment::getMerchantId, merchantIdList);
                }
            }
        } else {
            LoginUserVo loginUserVo = SecurityUtil.getLoginUserVo();
            Integer brandId = loginUserVo.getUser().getBrandId();
            if (brandId != null && brandId > 0) {
                List<Integer> merchantIdList = merchantService.list(new LambdaQueryWrapper<Merchant>()
                                .eq(Merchant::getBrandId, loginUserVo.getUser().getId())
                                .select(Merchant::getId))
                        .stream()
                        .map(Merchant::getId)
                        .collect(Collectors.toList());
                if (merchantIdList != null && merchantIdList.size() > 0) {
                    lqw.in(ZfbMonitorEquipment::getMerchantId, merchantIdList);
                }
            } else {
                lqw.eq(ZfbMonitorEquipment::getMerchantId, -1);
            }
        }
        if (ObjectUtil.isNotNull(searchRequest.getMerchantId()) && searchRequest.getMerchantId() > 0) {
            lqw.eq(ZfbMonitorEquipment::getMerchantId, searchRequest.getMerchantId());
        }
        if (ObjectUtil.isNotNull(searchRequest.getStatus())) {
            lqw.eq(ZfbMonitorEquipment::getOnlineStatus, searchRequest.getStatus());
        }

        return lqw.orderByAsc(ZfbMonitorEquipment::getId)
                .select(
                        ZfbMonitorEquipment::getId,
                        ZfbMonitorEquipment::getLicense,
                        ZfbMonitorEquipment::getEquipmentName,
                        ZfbMonitorEquipment::getOnlineStatus,
                        ZfbMonitorEquipment::getMerchantId,
                        ZfbMonitorEquipment::getEquipmentType
                );
    }

    /**
     * 定时任务：刷新设备在线状态
     */
    // @Scheduled(cron = "0 */30 * * * ?") // 每30分钟执行一次
    public void refreshOnlineStatus() {
        log.info("开始刷新设备在线状态...");
        try {
            // 查询所有设备
            List<ZfbMonitorEquipment> allDevices = zfbMonitorEquipmentMapper.selectList(new LambdaQueryWrapper<>());
            if (CollectionUtils.isEmpty(allDevices)) {
                log.warn("未找到任何设备，无需刷新在线状态");
                return;
            }
            // 批量处理设备状态
            Map<String, MonitorChannelEquipmentStatusVo> statusMap = allDevices.parallelStream()
                    .collect(Collectors.toConcurrentMap(
                            ZfbMonitorEquipment::getLicense,
                            device -> {
                                try {
                                    return getEquipmentStatus(device.getLicense());
                                } catch (Exception e) {
                                    log.error("设备 {} 状态查询失败", device.getLicense(), e);
                                    return null;
                                }
                            }
                    ));
            // 更新设备的在线状态
            List<ZfbMonitorEquipment> updateList = new ArrayList<>();
            for (ZfbMonitorEquipment device : allDevices) {
                MonitorChannelEquipmentStatusVo status = statusMap.get(device.getLicense());
                Integer isOnline = (status != null && !"2".equals(status.getStatus())) ? 1 : 0; // 1 表示在线，0 表示离线
                if (!Objects.equals(device.getOnlineStatus(), isOnline)) { // 只有状态变化时才更新
                    device.setOnlineStatus(isOnline);
                    device.setUpdateTime(LocalDateTime.now());
                    updateList.add(device);
                }
            }
            if (!updateList.isEmpty()) {
                // 批量更新数据库
                this.updateBatchById(updateList);
                log.info("成功更新 {} 个设备的在线状态", updateList.size());
            } else {
                log.info("所有设备在线状态未发生变化，无需更新");
            }

        } catch (Exception e) {
            log.error("刷新设备在线状态时发生异常", e);
        }
    }
    @Override
    public PageInfo<ZfbMonitorEquipment> getAdminPage(ZfbMonitorEquipmentRequest pageParamRequest) {
        com.github.pagehelper.Page<Merchant> page = null;
        List<ZfbMonitorEquipment> result = new ArrayList<>();
        List<ZfbMonitorEquipment> batch = new ArrayList<>();
        if (BrandUtil.isBrand()){
            List<Integer> merchantIdList = BrandUtil.getMerchantIdList();
            page = PageHelper.startPage(pageParamRequest.getPage(), pageParamRequest.getLimit());
            batch = zfbMonitorEquipmentMapper.selectList(
                    new LambdaQueryWrapper<ZfbMonitorEquipment>()
                            .in(ZfbMonitorEquipment::getOnlineStatus, 1, 3)
                            .in(ZfbMonitorEquipment::getMerchantId, merchantIdList)
                            .orderByAsc(ZfbMonitorEquipment::getId)
                            .select(ZfbMonitorEquipment::getId, ZfbMonitorEquipment::getLicense,ZfbMonitorEquipment::getOnlineStatus,ZfbMonitorEquipment::getMerchantId, ZfbMonitorEquipment::getEquipmentType)
            );
        }else {
            page = PageHelper.startPage(pageParamRequest.getPage(), pageParamRequest.getLimit());
            batch = zfbMonitorEquipmentMapper.selectList(
                    new LambdaQueryWrapper<ZfbMonitorEquipment>()
                            // 设备状态; 0:未知; 1: 在线; 2:离线; 3:休眠; 6:设备区域限制; 7:4G 卡限制
                            .in(ZfbMonitorEquipment::getOnlineStatus, 1,3)
                            .orderByAsc(ZfbMonitorEquipment::getId)
                            .select(ZfbMonitorEquipment::getId, ZfbMonitorEquipment::getLicense,ZfbMonitorEquipment::getOnlineStatus,ZfbMonitorEquipment::getMerchantId, ZfbMonitorEquipment::getEquipmentType)
            );
        }
            for (ZfbMonitorEquipment device : batch) {
                // 补充媒体地址
                MonitorChannelMediaAddressVo mediaAddress = monitorChannelHandle.getMediaAddress(
                        device.getLicense(), device.getEquipmentType());
                device.setMonitorMediaAddressList(Arrays.asList(mediaAddress));
                Merchant merchant = merchantService.getById(device.getMerchantId());
                List<ProMerchantProductResponse> merchantProductResponseList = productService.getRecommendedProductsByMerId(merchant.getId(), 6);
                device.setProList(merchantProductResponseList);
                device.setMerchantInfo(merchant);
                result.add(device);
            }
        return  CommonPage.copyPageInfo(page, result);
    }

    @Override
    public PageInfo<ZfbMonitorEquipment> getAdminPagePublicly(ZfbMonitorEquipmentRequest pageParamRequest) {
        LoginUserVo loginUserVo = SecurityUtil.getLoginUserVo();
        SystemAdmin currentAdmin = loginUserVo.getUser();
        Integer brandId = currentAdmin.getBrandId();
        if (currentAdmin.getType()==8){//品牌商超级管理员
            brandId = currentAdmin.getId();
        }

        com.github.pagehelper.Page<Merchant> page = null;
        List<ZfbMonitorEquipment> result = new ArrayList<>();
        List<ZfbMonitorEquipment> batch = new ArrayList<>();
        page = PageHelper.startPage(pageParamRequest.getPage(), pageParamRequest.getLimit());

        LambdaQueryWrapper<ZfbMonitorEquipment> lqw = new LambdaQueryWrapper<>();
        lqw.select(ZfbMonitorEquipment::getId, ZfbMonitorEquipment::getLicense,ZfbMonitorEquipment::getOnlineStatus,ZfbMonitorEquipment::getMerchantId, ZfbMonitorEquipment::getEquipmentType);
        // 设备状态; 0:未知; 1: 在线; 2:离线; 3:休眠; 6:设备区域限制; 7:4G 卡限制
        lqw.in(ZfbMonitorEquipment::getOnlineStatus, 1,3);


        if (brandId!=null && brandId>0){// 品牌商大于0，总平台是0
            List<Merchant> merchants = merchantService.getBrandMerchant(brandId);
            if(merchants!=null && merchants.size()>0){
                List<Integer> merchantIds = merchants.stream().map(Merchant::getId).collect(Collectors.toList());
                lqw.in(ZfbMonitorEquipment::getMerchantId, merchantIds);
            }else{//品牌商没有商户
                lqw.eq(ZfbMonitorEquipment::getMerchantId, -1);
            }
        }


        lqw.orderByAsc(ZfbMonitorEquipment::getId);

        batch = zfbMonitorEquipmentMapper.selectList(lqw);
        for (ZfbMonitorEquipment device : batch) {
            // 补充媒体地址
            MonitorChannelMediaAddressVo mediaAddress = monitorChannelHandle.getMediaAddress(
                    device.getLicense(), device.getEquipmentType());
            device.setMonitorMediaAddressList(Arrays.asList(mediaAddress));
            Merchant merchant = merchantService.getById(device.getMerchantId());
            List<ProMerchantProductResponse> merchantProductResponseList = productService.getRecommendedProductsByMerId(merchant.getId(), 6);
            device.setProList(merchantProductResponseList);
            device.setMerchantInfo(merchant);
            result.add(device);
        }
        return  CommonPage.copyPageInfo(page, result);
    }


    @Override
    public PageInfo<ZfbMonitorEquipment> getAdminPageMerchant(ZfbMonitorEquipmentRequest pageParamRequest) {
        SystemAdmin systemAdmin = SecurityUtil.getLoginUserVo().getUser();
        Merchant merchantTmp = merchantService.getById(systemAdmin.getMerId());
        List<Integer> merchantIdList = merchantService.list(new LambdaQueryWrapper<Merchant>()
                        .eq(Merchant::getBrandId, merchantTmp.getBrandId())
                        .select(Merchant::getId))
                .stream()
                .map(Merchant::getId)
                .collect(Collectors.toList());

        com.github.pagehelper.Page<Merchant> page = null;
        List<ZfbMonitorEquipment> result = new ArrayList<>();
        List<ZfbMonitorEquipment> batch = new ArrayList<>();
        page = PageHelper.startPage(pageParamRequest.getPage(), pageParamRequest.getLimit());
        batch = zfbMonitorEquipmentMapper.selectList(
            new LambdaQueryWrapper<ZfbMonitorEquipment>()
                    // 设备状态; 0:未知; 1: 在线; 2:离线; 3:休眠; 6:设备区域限制; 7:4G 卡限制
                    .in(ZfbMonitorEquipment::getMerchantId, merchantIdList)
                    .in(ZfbMonitorEquipment::getOnlineStatus, 1,3)
                    .orderByAsc(ZfbMonitorEquipment::getId)
                    .select(ZfbMonitorEquipment::getId, ZfbMonitorEquipment::getLicense,ZfbMonitorEquipment::getOnlineStatus,ZfbMonitorEquipment::getMerchantId, ZfbMonitorEquipment::getEquipmentType)
        );
        for (ZfbMonitorEquipment device : batch) {
            // 补充媒体地址
            MonitorChannelMediaAddressVo mediaAddress = monitorChannelHandle.getMediaAddress(
                    device.getLicense(), device.getEquipmentType());
            device.setMonitorMediaAddressList(Arrays.asList(mediaAddress));
            Merchant merchant = merchantService.getById(device.getMerchantId());
            List<ProMerchantProductResponse> merchantProductResponseList = productService.getRecommendedProductsByMerId(merchant.getId(), 6);
            device.setProList(merchantProductResponseList);
            device.setMerchantInfo(merchant);
            result.add(device);
        }
        return  CommonPage.copyPageInfo(page, result);
    }


    /**
     * 5.5.4.2 重启设备
     * 功能说明：
     * 1、重启设备；
     * 2、请求URL；/GMModule/V3/Device/RebootDevice
     *
     * @param requestVo
     * @return
     */
    @Override
    public JSONObject v3RebootDevice(MonitorRebootDeviceVo requestVo, int equipmentType) {
        return monitorChannelHandle.v3RebootDevice(requestVo, equipmentType);
    }

    /**
     * 5.5.4.3 检测设备版本是否可升级
     * 功能说明：
     * 1、后台比较设备当前版本号与后台版本号，当后台版本呢大于当前版本，则可升级；
     * 比较方式：strcmp("当前版本号","后台版本号") > 0 ；
     * 2、请求 URL；；/GMModule/V3/Device/CheckDeviceUpgradeVersion
     *
     * @param requestVo
     * @return
     */
    @Override
    public JSONObject v3CheckDeviceUpgradeVersion(MonitorBaseVo requestVo, int equipmentType) {
        return monitorChannelHandle.v3CheckDeviceUpgradeVersion(requestVo, equipmentType);
    }


    /**
     * 5.5.4.4 通知设备升级到最新版本
     * 功能说明：
     * 1、当检测设备有新版后，通知设备进行 OTA；
     * 2、请求 URL；/GMModule/V3/Device/NoticeUpgradeDeviceToLatestVersion
     *
     * @param requestVo
     * @return
     */
    @Override
    public JSONObject v3NoticeUpgradeDeviceToLatestVersion(MonitorBaseVo requestVo, int equipmentType) {
        return monitorChannelHandle.v3NoticeUpgradeDeviceToLatestVersion(requestVo, equipmentType);
    }


    /**
     * 5.5.4.17 获取 TF 卡信息
     * 功能说明：
     * 1、查询 TF 卡的容量信息；
     * 2、请求 URL；/GMModule/V3/Device/GetSDCardInfo
     *
     * @param requestVo
     * @returnF
     */
    @Override
    public MonitorGetSDCardInfoResultVo v3GetSDCardInfo(MonitorBaseVo requestVo, int equipmentType) {
        return monitorChannelHandle.v3GetSDCardInfo(requestVo, equipmentType);
    }

    /**
     * 5.5.4.18 格式化 TF 卡
     * 功能说明：
     * 1、格式话设备 TF 卡，TF 卡数据将会全部丢失；
     * 2、请求 URL；/GMModule/V3/Device/FormatSDCard
     *
     * @param requestVo
     * @return
     */
    @Override
    public JSONObject v3FormatSDCard(MonitorBaseVo requestVo, int equipmentType) {
        return monitorChannelHandle.v3FormatSDCard(requestVo, equipmentType);
    }

    /**
     * 5.5.4.19 设置设备名称
     * 功能说明：
     * 1、修改设备的名称；
     * 2、请求 URL；/GMModule/V3/Device/SetDeviceName
     *
     * @param requestVo
     * @return
     */
    @Override
    public JSONObject v3SetDeviceName(MonitorSetDeviceNameVo requestVo, int equipmentType) {
        return monitorChannelHandle.v3SetDeviceName(requestVo, equipmentType);
    }

    /**
     * 5.5.4.26 控制设备进行放大和缩小
     * 功能说明：
     * 1、当设备具有变焦能力的时候，通过该接口通知设备变焦，可以是电子变焦或光学变
     * 焦；
     * 2、请求 URL；/GMModule/V3/Device/AdjustFocalLength
     *
     * @param requestVo
     * @return
     */
    @Override
    public JSONObject v3AdjustFocalLength(MonitorAdjustFocalLengthVo requestVo, int equipmentType) {
        return monitorChannelHandle.v3AdjustFocalLength(requestVo, equipmentType);
    }


    /**
     * 5.5.4.27 设置电池工作模式
     * 功能说明：
     * 1、设置电池摄像机的工作模式，前提是设备支持工作模式切换；
     * 2、请求 URL；/GMModule/V3/Device/SetBatteryWorkMode
     *
     * @param requestVo
     * @return
     */
    @Override
    public JSONObject v3SetBatteryWorkMode(MonitorSetBatteryWorkModeVo requestVo, int equipmentType) {
        return monitorChannelHandle.v3SetBatteryWorkMode(requestVo, equipmentType);
    }

    /**
     * 查询客户机要展示的监控列表
     * @param pageParamRequest
     * @return
     */
    @Override
    public PageInfo<ZfbMonitorEquipment> getClientPage(ZfbMonitorEquipmentRequest pageParamRequest) {
        Integer brandId = pageParamRequest.getBrandId();
        List<ZfbMonitorEquipment> batch = Collections.emptyList(); // 初始化为空列表
        boolean queryAll = true; // 标记是否需要查询所有设备
        List<Integer> merchantIdList = Collections.emptyList();

        // 1. 判断是否有有效的 brandId 传入
        if (brandId != null && brandId > 0) {
            SystemAdmin systemAdmin = systemAdminService.getOne(
                    new LambdaQueryWrapper<SystemAdmin>()
                            .eq(SystemAdmin::getBrandId, brandId));
            // 2. 查询指定品牌下所有未关闭的商家ID
            merchantIdList = merchantService.list(new LambdaQueryWrapper<Merchant>()
                            .eq(Merchant::getBrandId, systemAdmin.getId())
                            .eq(Merchant::getIsSwitch, 1) // 假设 1 表示未关闭
                            .eq(Merchant::getIsDel, 0)
                            .select(Merchant::getId))
                    .stream()
                    .map(Merchant::getId)
                    .collect(Collectors.toList());

            // 3. 如果找到了对应的商家
            if (CollectionUtils.isNotEmpty(merchantIdList)) {
                // 4. 尝试查询这些商家下是否有在线设备
                LambdaQueryWrapper<ZfbMonitorEquipment> queryWrapper = createBaseEquipmentQuery();
                queryWrapper.in(ZfbMonitorEquipment::getMerchantId, merchantIdList).select(ZfbMonitorEquipment::getId);
                Integer count = zfbMonitorEquipmentMapper.selectCount(queryWrapper);

                // 5. 如果查询到了设备，则不需要查询所有设备了
                if (count != null && count > 0) {
                    queryAll = false;
                }
                // 注意：如果 batch 为空（即品牌下有商家但无在线设备），queryAll 仍然是 true，会触发下面的 fallback
            }
            // 如果没有找到商家 (merchantIdList 为空), queryAll 仍然是 true，也会触发 fallback
        }

        // 6. Fallback 逻辑：如果需要查询所有设备 (未传 brandId / brandId 无效 / 未找到商家 / 品牌下商家无在线设备)
        com.github.pagehelper.Page<ZfbMonitorEquipment> page = PageHelper.startPage(pageParamRequest.getPage(), pageParamRequest.getLimit());
        if (queryAll) {
            LambdaQueryWrapper<ZfbMonitorEquipment> queryWrapper = createBaseEquipmentQuery();
            batch = zfbMonitorEquipmentMapper.selectList(queryWrapper);
        } else {
            LambdaQueryWrapper<ZfbMonitorEquipment> queryWrapper = createBaseEquipmentQuery();
            queryWrapper.in(ZfbMonitorEquipment::getMerchantId, merchantIdList);
            batch = zfbMonitorEquipmentMapper.selectList(queryWrapper);
        }

        String indexPageUrl = "/pages/merchant/home/index?id=";
        for (ZfbMonitorEquipment device : batch) {
            // 补充媒体地址
            MonitorChannelMediaAddressVo mediaAddress = monitorChannelHandle.getMediaAddress(
                    device.getLicense(), device.getEquipmentType());
            device.setMonitorMediaAddressList(Arrays.asList(mediaAddress));
            Merchant merchant = merchantService.getById(device.getMerchantId());
            List<ProMerchantProductResponse> merchantProductResponseList = productService.getRecommendedProductsByMerId(merchant.getId(), 6);
            device.setProList(merchantProductResponseList);
            device.setMerchantInfo(merchant);
            if (merchant.getBrandId() != null) {
                SystemAdmin systemAdmin = systemAdminService.getById(merchant.getBrandId());
                if (systemAdmin.getBrandId() != null && systemAdmin.getBrandId() > 0) {
                    Brand brand = brandService.getById(systemAdmin.getBrandId());
                    device.setBrand(brand);
                    String url = "https://" + brand.getShareUrl() + indexPageUrl + merchant.getId();
                    QrCodeVo qrCodeVo = qrCodeService.strToBase64(url, pageParamRequest.getWidth(), pageParamRequest.getHeight());
                    device.setQrCode(qrCodeVo.getCode());
                }
            }
        }

        return  CommonPage.copyPageInfo(page, batch);
    }

    /**
     * 创建基础的设备查询条件 (在线状态、排序、选择字段)
     * @return LambdaQueryWrapper<ZfbMonitorEquipment>
     */
    private LambdaQueryWrapper<ZfbMonitorEquipment> createBaseEquipmentQuery() {
        return new LambdaQueryWrapper<ZfbMonitorEquipment>()
                // 设备状态; 1: 在线; 3: 休眠 (根据需求，这两个状态视为"在线")
                .in(ZfbMonitorEquipment::getOnlineStatus, 1, 3)
                .orderByAsc(ZfbMonitorEquipment::getId)
                .select(
                        ZfbMonitorEquipment::getId,
                        ZfbMonitorEquipment::getLicense,
                        ZfbMonitorEquipment::getEquipmentName,
                        ZfbMonitorEquipment::getOnlineStatus,
                        ZfbMonitorEquipment::getMerchantId,
                        ZfbMonitorEquipment::getEquipmentType
                );
    }

    @Override
    public ZfbMonitorLightUserInfoResponse lightUserInfo(MonitorControlLightUserinfoRequest request, String orderNo) {
        // 可优化
//        ZfbMonitorEquipment monitorEquipment = zfbMonitorEquipmentService.getOne(new LambdaQueryWrapper<ZfbMonitorEquipment>()
//                .select(ZfbMonitorEquipment::getId)
//                .eq(ZfbMonitorEquipment::getLicense, request.getLicense())
//        );
//        if (ObjectUtil.isNull(monitorEquipment)) {
//            throw new AppException(CommonResultCode.VALIDATE_FAILED.setMessage("查询不到监控设备"));
//        }
//        ZfbMonitorDeviceBind bind = zfbMonitorDeviceBindService.getOne(new LambdaQueryWrapper<ZfbMonitorDeviceBind>()
//                .select(ZfbMonitorDeviceBind::getDeviceId)
//                .eq(ZfbMonitorDeviceBind::getMeid, monitorEquipment.getId())
//                .eq(ZfbMonitorDeviceBind::getIsDeleted, false)
//        );
//        if (ObjectUtil.isNull(bind)) {
//            throw new AppException(CommonResultCode.VALIDATE_FAILED.setMessage("查询不到绑定网关"));
//        }

        ZfbMonitorLightUserInfoResponse response = new ZfbMonitorLightUserInfoResponse();
        response.setIsView(false);
        String userKey = "monitor:" + request.getLicense().trim() + ":view-user";
        Object o = redisUtil.get(userKey);
        if (ObjectUtil.isNotNull(o)) {
            response.setIsView(true);
            response.setNickname(o.toString());
            // 是否自己在看
            LambdaQueryWrapper<MerchantOrder> lqw = Wrappers.lambdaQuery();
            lqw.eq(MerchantOrder::getOrderNo, orderNo);
            lqw.last("limit 1");
            MerchantOrder one = merchantOrderService.getOne(lqw);
            if (o.toString().equals(one.getRealName())) {
                response.setIsOwn(true);

                String key = "monitor:" + request.getLicense() + ":send";
                // 检查是否重复发送
                Object statusObj = redisUtil.get(key);
                if (ObjectUtil.isNotNull(statusObj)) {
                    response.setMac(statusObj.toString());
                }
            }
            return response;
        }
        return response;
    }

    @Override
    public String getLicenseById(Integer id) {
        ZfbMonitorEquipment monitorEquipment = zfbMonitorEquipmentService.getOne(new LambdaQueryWrapper<ZfbMonitorEquipment>()
                .select(ZfbMonitorEquipment::getLicense)
                .eq(ZfbMonitorEquipment::getId, id)
        );
        if (ObjectUtil.isNotNull(monitorEquipment)) {
            return monitorEquipment.getLicense();
        }
        return null;
    }

    @Override
    public ZfbMonitorLightResultResponse lightResult(MonitorControlLightRequest request, String orderNo) {
        Order order = orderService.getByOrderNo(orderNo);
        Merchant merchant = merchantService.getById(order.getMerId());
        ZfbMonitorEquipment monitorEquipment = zfbMonitorEquipmentService.getOne(new LambdaQueryWrapper<ZfbMonitorEquipment>()
                .select(ZfbMonitorEquipment::getId)
                .eq(ZfbMonitorEquipment::getLicense, request.getLicense())
                .eq(ZfbMonitorEquipment::getMerchantId, merchant.getId())
        );
        if (ObjectUtil.isNull(monitorEquipment)) {
            throw new AppException(CommonResultCode.VALIDATE_FAILED.setMessage("查询不到监控设备"));
        }
        ZfbMonitorDeviceBind bind = zfbMonitorDeviceBindService.getOne(new LambdaQueryWrapper<ZfbMonitorDeviceBind>()
                .select(ZfbMonitorDeviceBind::getDeviceId)
                .eq(ZfbMonitorDeviceBind::getMeid, monitorEquipment.getId())
                .eq(ZfbMonitorDeviceBind::getIsDeleted, false)
        );
        if (ObjectUtil.isNull(bind)) {
            throw new AppException(CommonResultCode.VALIDATE_FAILED.setMessage("查询不到绑定网关"));
        }
        Device device = deviceService.getById(bind.getDeviceId());
        String imei = device.getImei();

        ZfbMonitorLightResultResponse response = new ZfbMonitorLightResultResponse();

        String resKey = "monitor:" + imei + ":" + request.getDeviceMac() + ":status:res";
        redisUtil.get(resKey);
        Object statusObj = redisUtil.get(resKey);
        if (statusObj != null) {
            String s = String.valueOf(statusObj);
            if (s.equals("OK")) {
                // 成功
                response.setIsSucc(true);
                response.setRes("成功");
                return response;
            } else {
                // 失败
                response.setIsSucc(false);
                response.setRes("失败");
                return response;
            }
        }
        return response;
    }

    @Override
    public ZfbMonitorEquipmentAvailableResponse getAvailableList(String[] license, Integer num) {
        if (num != null && num > 0) {
            return getAvailableListByNum(num);
        }
        ZfbMonitorEquipmentAvailableResponse response = new ZfbMonitorEquipmentAvailableResponse();
        List<ZfbMonitorEquipment> list = zfbMonitorEquipmentService.list(new LambdaQueryWrapper<ZfbMonitorEquipment>()
                .select(ZfbMonitorEquipment::getId, ZfbMonitorEquipment::getLicense,ZfbMonitorEquipment::getOnlineStatus,ZfbMonitorEquipment::getMerchantId, ZfbMonitorEquipment::getEquipmentType)
                .in(ZfbMonitorEquipment::getLicense, license));
        if (CollUtil.isNotEmpty(list)) {
            List<String> failList = list.stream().filter(zfbMonitorEquipment -> zfbMonitorEquipment.getOnlineStatus() != 1).map(ZfbMonitorEquipment::getLicense).distinct().collect(Collectors.toList());
            if (CollUtil.isEmpty(failList)) {
                // 直接返回成功
                response.setIsFullSuccess(true);
                return response;
            }
            List<ZfbMonitorEquipment> succList = list.stream().filter(zfbMonitorEquipment -> zfbMonitorEquipment.getOnlineStatus().equals(1))
                    .distinct().collect(Collectors.toList());

            Date twoHoursAgo = DateUtil.offsetHour(new Date(), -2);
            // 从列表中拿几个好的设备
            List<ZfbMonitorEquipment> deviceList = zfbMonitorEquipmentService.list(new LambdaQueryWrapper<ZfbMonitorEquipment>()
                    .select(ZfbMonitorEquipment::getId, ZfbMonitorEquipment::getLicense,ZfbMonitorEquipment::getOnlineStatus,ZfbMonitorEquipment::getMerchantId, ZfbMonitorEquipment::getEquipmentType)
                    .notIn(ZfbMonitorEquipment::getLicense, license)
                    .in(ZfbMonitorEquipment::getOnlineStatus, 1,3)
                    .apply("TIMESTAMPDIFF(SECOND, last_online_time, update_time) > 30")
                    .apply("date_format(last_online_time, '%Y-%m-%d %H:%i:%s') > {0}", DateUtil.format(twoHoursAgo, "yyyy-MM-dd HH:mm:ss"))
                    .orderByAsc(ZfbMonitorEquipment::getLastOnlineTime)
                    .last("limit " + (failList.size()))
            );
            if (succList == null) {
                succList = new ArrayList<>();
            }
            if (CollUtil.isNotEmpty(deviceList)) {
                succList.addAll(deviceList);
            }
            for (ZfbMonitorEquipment device : succList) {
                // 补充媒体地址
                MonitorChannelMediaAddressVo mediaAddress = monitorChannelHandle.getMediaAddress(
                        device.getLicense(), device.getEquipmentType());
                device.setMonitorMediaAddressList(Arrays.asList(mediaAddress));
                Merchant merchant = merchantService.getById(device.getMerchantId());
                List<ProMerchantProductResponse> merchantProductResponseList = productService.getRecommendedProductsByMerId(merchant.getId(), 1);
                device.setProList(merchantProductResponseList);
                device.setMerchantInfo(merchant);
            }
            response.setIsFullSuccess(false);
            response.setDeviceList(succList);
            return response;
        }
        return null;
    }

    private ZfbMonitorEquipmentAvailableResponse getAvailableListByNum(Integer num) {
        ZfbMonitorEquipmentAvailableResponse response = new ZfbMonitorEquipmentAvailableResponse();
        Date twoHoursAgo = DateUtil.offsetHour(new Date(), -2);
        // 从列表中拿几个好的设备
        List<ZfbMonitorEquipment> deviceList = zfbMonitorEquipmentService.list(new LambdaQueryWrapper<ZfbMonitorEquipment>()
                .select(ZfbMonitorEquipment::getId, ZfbMonitorEquipment::getLicense,ZfbMonitorEquipment::getOnlineStatus,ZfbMonitorEquipment::getMerchantId, ZfbMonitorEquipment::getEquipmentType)
                .in(ZfbMonitorEquipment::getOnlineStatus, 1,3)
                .apply("TIMESTAMPDIFF(SECOND, last_online_time, update_time) > 30")
                .apply("date_format(last_online_time, '%Y-%m-%d %H:%i:%s') > {0}", DateUtil.format(twoHoursAgo, "yyyy-MM-dd HH:mm:ss"))
                .orderByAsc(ZfbMonitorEquipment::getLastOnlineTime)
                .last("limit " + num)
        );
        if(CollUtil.isNotEmpty(deviceList)){
            for (ZfbMonitorEquipment device : deviceList) {
                // 补充媒体地址
                MonitorChannelMediaAddressVo mediaAddress = monitorChannelHandle.getMediaAddress(
                        device.getLicense(), device.getEquipmentType());
                device.setMonitorMediaAddressList(Arrays.asList(mediaAddress));
                Merchant merchant = merchantService.getById(device.getMerchantId());
                List<ProMerchantProductResponse> merchantProductResponseList = productService.getRecommendedProductsByMerId(merchant.getId(), 1);
                device.setProList(merchantProductResponseList);
                device.setMerchantInfo(merchant);
            }
        }

        response.setIsFullSuccess(false);
        response.setDeviceList(deviceList);
        return response;
    }

    @Override
    public List<ZfbMonitorEquipmentStatusResponse> getStatus(String[] license) {
        List<ZfbMonitorEquipment> list = zfbMonitorEquipmentService.list(new LambdaQueryWrapper<ZfbMonitorEquipment>()
                .select(ZfbMonitorEquipment::getId, ZfbMonitorEquipment::getLicense,ZfbMonitorEquipment::getOnlineStatus,
                        ZfbMonitorEquipment::getLastOnlineTime)
                .in(ZfbMonitorEquipment::getLicense, license));
        if (CollUtil.isNotEmpty(list)) {
            List<ZfbMonitorEquipmentStatusResponse> responseList = new ArrayList<>();
            for (ZfbMonitorEquipment zfbMonitorEquipment : list) {
                ZfbMonitorEquipmentStatusResponse response = new ZfbMonitorEquipmentStatusResponse();
                BeanUtils.copyProperties(zfbMonitorEquipment, response);
                responseList.add(response);
            }
            return responseList;
        }
        return null;
    }
}
